package net.stuffrepos.bricknetcenter.gui.inventories;

import java.awt.GridBagConstraints;
import java.awt.event.ActionEvent;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import net.stuffrepos.bricknetcenter.database.DataManager;
import net.stuffrepos.bricknetcenter.database.schema.Transfer;
import net.stuffrepos.bricknetcenter.database.schema.TransferObject;
import net.stuffrepos.bricknetcenter.gui.FormatHelper;
import net.stuffrepos.bricknetcenter.gui.MainFrame;
import net.stuffrepos.bricknetcenter.util.gui.inputtable.ObjectsTable;
import net.stuffrepos.bricknetcenter.util.gui.GapedPanel;
import net.stuffrepos.bricknetcenter.util.gui.inputcomponent.InputComponent;
import net.stuffrepos.bricknetcenter.util.gui.inputcomponent.InputComponentFactory;
import net.stuffrepos.util.cache.CacheableValue;
import net.stuffrepos.util.listeners.Listener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author Eduardo H. Bogoni <eduardobogoni@gmail.com>
 */
public class TransferDetailPanel extends GapedPanel {

    private static final Log log = LogFactory.getLog(TransferDetailPanel.class);
    private final InventoriesFrame inventoriesFrame;
    private Transfer transfer;
    private InputComponent comments;
    private InputComponent createdOn;
    private InputComponent modifiedOn;
    private InputComponent date;
    private javax.swing.JLabel title;
    private ObjectsTable<TransferObject> objectsTable;
    private final CacheableValue<ObjectPicker> objectPicker = new CacheableValue<ObjectPicker>() {

        @Override
        protected ObjectPicker calculate() {
            return new ObjectPicker(MainFrame.getInstance(), true);
        }
    };

    public TransferDetailPanel(InventoriesFrame inventoriesFrame) {
        assert inventoriesFrame != null;
        this.inventoriesFrame = inventoriesFrame;
        initComponents();        
        FormatHelper.formatTitleLabel(title);
    }
    private Action addObjectAction = new AbstractAction("Add Object") {

        @Override
        public void actionPerformed(ActionEvent e) {
            objectsTable.addObject(new TransferObject());
        }
    };
    private Action objectPickerAction = new AbstractAction("Object Picker") {

        @Override
        public void actionPerformed(ActionEvent e) {
            openObjectPicker();
        }
    };
    private Action deleteObjectAction = new AbstractAction("Delete Object") {

        @Override
        public void actionPerformed(ActionEvent e) {
            objectsTable.removeSelectedObjects();
        }
    };
    private Action deleteAllObjectsAction = new AbstractAction("Delete All") {

        @Override
        public void actionPerformed(ActionEvent e) {
            objectsTable.clearObjects();
            //objectsTable.repaint();
        }
    };
    private Action saveAction = new AbstractAction("Save") {

        @Override
        public void actionPerformed(ActionEvent e) {
            try {
                DataManager.getInstance().saveTransfer(getData());
            } catch (Exception ex) {
                MainFrame.getInstance().registerException("Erro on saving Transfer.", ex);
            }
        }
    };
    private Action cancelAction = new AbstractAction("Cancel") {

        @Override
        public void actionPerformed(ActionEvent e) {
            inventoriesFrame.showPanelFromSelectedNode();
        }
    };

    private void initComponents() {

        title = new javax.swing.JLabel("Transfer");
        JButton cancel = new javax.swing.JButton(cancelAction);
        JButton save = new javax.swing.JButton(saveAction);
        JButton objectPickerButton = new javax.swing.JButton(objectPickerAction);
        JButton addObjectButton = new javax.swing.JButton(addObjectAction);
        JButton deleteObjectButton = new JButton(deleteObjectAction);
        JButton deleteAllObjectsButton = new JButton(deleteAllObjectsAction);

        objectsTable = new ObjectsTable<TransferObject>(TransferObject.class, new String[]{
                    "type",
                    "code",
                    "color",
                    "quantity",
                    "state",
                    "comments"
                });

        JScrollPane objectsTableScrollPane = new JScrollPane(objectsTable);
        objectsTable.setFillsViewportHeight(true);

        createdOn = InputComponentFactory.newInput(Transfer.class, "createdOn").setEditable(false);
        modifiedOn = InputComponentFactory.newInput(Transfer.class, "modifiedOn").setEditable(false);
        comments = InputComponentFactory.newInput(Transfer.class, "comments");
        date = InputComponentFactory.newInput(Transfer.class, "date");


        this.setConstraintProperty(ConstraintProperty.WidthX, 1.0);

        this.getRow(0).
                getSub(0).add(title, GridBagConstraints.REMAINDER);

        this.getRow(1).
                getSub(0).add(date, 5).
                getSub(5).add(comments, 5, 3);

        this.getRow(2).
                getSub(0).add(createdOn, 5);

        this.getRow(3).
                getSub(0).add(modifiedOn, 5);

        this.getRow(4).
                getSub(0).add(addObjectButton, 1).
                getSub(1).add(deleteObjectButton, 1).
                getSub(2).add(objectPickerButton, 2).
                getSub(4).add(deleteAllObjectsButton, 2).
                getSub(6).add(save, 2).
                getSub(8).add(cancel, 2);
        this.getRow(5).
                setConstraintProperty(ConstraintProperty.WidthY, 1.0).
                setConstraintProperty(ConstraintProperty.GridWidth, GridBagConstraints.REMAINDER).
                setConstraintProperty(ConstraintProperty.Fill, GridBagConstraints.BOTH).
                getSub(0).add(objectsTableScrollPane);

        objectsTable.getModel().addTableModelListener(new TableModelListener() {

            @Override
            public void tableChanged(TableModelEvent e) {
                deleteAllObjectsAction.setEnabled(!objectsTable.getObjects().isEmpty());
            }
        });

        objectsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {

            @Override
            public void valueChanged(ListSelectionEvent e) {
                deleteObjectAction.setEnabled(!objectsTable.getSelectionModel().isSelectionEmpty());
            }
        });

        objectsTable.addValueChangeListener(new Listener<ObjectsTable<TransferObject>>() {

            @Override
            public void onChange(ObjectsTable<TransferObject> t) {
                updateSaveActionEnabled();
            }
        });

        comments.addValueListener(new Listener<InputComponent>() {

            @Override
            public void onChange(InputComponent t) {
                updateSaveActionEnabled();
            }
        });

        date.addValueListener(new Listener<InputComponent>() {

            @Override
            public void onChange(InputComponent t) {
                updateSaveActionEnabled();
            }
        });
    }

    private void openObjectPicker() {
        objectPicker.getValue().setVisible(true);
    }

    public Transfer getData() {
        transfer.setComments((String) comments.getValue());
        transfer.setDate((Date) date.getValue());

        Set<TransferObject> guiObjects = new HashSet<TransferObject>();
        for (TransferObject guiObject : objectsTable.getData()) {

            guiObjects.add(guiObject);
            if (!transfer.getObjects().contains(guiObject)) {
                transfer.getObjects().add(guiObject);
            }

        }

        Set<TransferObject> toRemove = new HashSet<TransferObject>();
        for (TransferObject transferObject : transfer.getObjects()) {
            if (!guiObjects.contains(transferObject)) {
                toRemove.add(transferObject);
            }
        }

        transfer.getObjects().removeAll(toRemove);

        return transfer;
    }

    public void setData(Transfer transfer) {
        objectsTable.clearObjects();
        this.transfer = transfer;
        createdOn.setValue(transfer.getCreatedOn());
        modifiedOn.setValue(transfer.getModifiedOn());
        comments.setValue(transfer.getComments());
        date.setValue(transfer.getDate());
        for (TransferObject object : transfer.getObjects()) {
            objectsTable.addObject(object);
        }
    }

    private void updateSaveActionEnabled() {
        saveAction.setEnabled(objectsTable.isObjectsValid() && comments.isValidValue() && date.isValidValue());
    }
}
